# -*- coding: utf-8 -*-  # 指定文件编码为utf-8，这对于包含非ASCII字符的文件很重要

# 导入必要的库和模块
from joblib.numpy_pickle_utils import xrange  # 注意：在较新的Python版本中，xrange已经被移除，使用range即可
from numpy import array  # 导入NumPy的array函数
from sklearn.ensemble import RandomForestClassifier  # 导入随机森林分类器
from sklearn import tree  # 导入决策树模块（虽然这里只使用了tree.export_graphviz）
from sklearn.tree import export_graphviz  # 导入导出决策树为Graphviz格式的函数（重复导入，因为已经从sklearn.tree导入了tree模块）
import graphviz  # 导入Graphviz库，用于生成和显示决策树图形
import matplotlib.pyplot as plt  # 导入matplotlib的pyplot模块，用于绘图

# 处理数据
filename = '4.4.3-wine.csv'  # 指定CSV文件的路径
data = []  # 初始化特征数据列表
label = []  # 初始化标签数据列表
with open(filename, 'r') as f:  # 以读取模式打开文件
    for line in f.readlines():  # 逐行读取文件
        x = line[:-3].split(',')  # 去掉行尾的换行符和可能的逗号，然后按逗号分割
        data.append(x)  # 将分割后的列表添加到特征数据列表中
        y = line[-2]  # 获取倒数第二个字符作为标签（这里可能有误，通常应该是整数值，但这里取的是字符）
        print("y:" + y)  # 打印标签（这里将显示字符，可能不是预期的整数值）
        label.append(y)  # 将标签添加到标签数据列表中

# 将列表转换为NumPy数组，并进行类型转换
data = array(data)
label = array(label)
data = data[:, :].astype(float)  # 将特征数据转换为浮点数类型
label = label[:].astype(int)  # 尝试将标签数据转换为整数类型（但之前从字符串转换可能失败，如果y不是数字字符串）

# 划分训练集和测试集
data_train = data[:int(data.shape[0] * 0.8)]  # 前80%作为训练集
label_train = label[:int(label.shape[0] * 0.8)]  # 对应的标签
data_test = data[int(data.shape[0] * 0.8):]  # 后20%作为测试集
label_test = label[int(label.shape[0] * 0.8):]  # 对应的标签

# 训练模型
clf = RandomForestClassifier(n_estimators=3)  # 创建一个随机森林分类器，包含3棵树
clf.fit(data_train, label_train)  # 使用训练集训练模型
label_predict = clf.predict(data_test)  # 对测试集进行预测

# 与真实标签比较
x = range(data_test.shape[0])  # 创建一个与测试集样本数量相同的范围对象（注意：在Python 3中应使用range而非xrange）
fig = plt.figure()  # 创建一个图形对象
ax1 = fig.add_subplot(211)  # 添加第一个子图（2行1列的第一个）
ax2 = fig.add_subplot(212)  # 添加第二个子图（2行1列的第二个）
ax1.set_title('Predict cluster')  # 设置第一个子图的标题
ax2.set_title('True cluster')  # 设置第二个子图的标题
plt.xlabel('samples')  # 设置x轴标签（这将同时应用于两个子图）
plt.ylabel('label')  # 设置y轴标签（同样，这将同时应用于两个子图，但通常最好在每个子图上分别设置）
ax1.scatter(x, label_predict, c=label_predict, marker='o')  # 在第一个子图上绘制预测标签的散点图
ax2.scatter(x, label_test, c=label_test, marker='s')  # 在第二个子图上绘制真实标签的散点图
plt.show()  # 显示图形

# 为随机森林中的每棵决策树生成图形表示
# 注意：这里的代码可能无法正常工作，因为clf.estimators_中的树可能不是直接可用于export_graphviz的
# 通常，我们需要单独训练每棵树，或者确保clf.estimators_中的树是以正确的方式存储的
for i in xrange(len(clf.estimators_)):  # 遍历随机森林中的每棵树（但注意xrange的问题）
    dot_data = tree.export_graphviz(clf.estimators_[i], out_file=None,
                                    filled=True, rounded=True,
                                    special_characters=True)  # 导出树为Graphviz格式
    graph = graphviz.Source(dot_data)  # 创建一个Graphviz Source对象
    graph.render('CLF%d_RF.dot' % (i + 1), "img/", view=True)  # 将图形渲染为文件，并尝试打开查看